﻿using System.Collections.Immutable;
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
using UIOC.CodeAnalysis.Diagnostics;
using UIOC.CodeAnalysis.Extensions;

namespace UIOC.CodeAnalysis.Analyzers;

// 分析器：检测标记了 [FileField] 的字段使用
[DiagnosticAnalyzer(LanguageNames.CSharp)]
internal sealed class FileFieldAttributeAnalyzer : DiagnosticAnalyzer {

    public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics
        => ImmutableArray.Create(FileFieldAttributeRestrictionDiagnostic.Rule);

    public override void Initialize(AnalysisContext context) {
        context.EnableConcurrentExecution();
        context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
        context.RegisterSyntaxNodeAction(AnalyzeAccess, SyntaxKind.SimpleMemberAccessExpression);
        context.RegisterSyntaxNodeAction(AnalyzeAccess, SyntaxKind.IdentifierName);
    }

    /// <summary>
    /// 分析成员访问表达式（如 obj.fieldName）
    /// </summary>
    private void AnalyzeAccess(SyntaxNodeAnalysisContext context) {
        var compilation = context.Compilation;
        var assembly = compilation.Assembly;
        if (assembly.IsIgnore()) {
            return;
        }

        var fileFieldAttributeSymbol = compilation.GetTypeByMetadataName(AttributeFullNames.FileField);
        if (fileFieldAttributeSymbol == null) {
            return;
        }

        IFieldSymbol fieldSymbol = null;
        Location location = null;
        if (context.Node is MemberAccessExpressionSyntax memberAccess) {
            var targetSymbol = context.SemanticModel.GetSymbolInfo(memberAccess).Symbol;
            if (targetSymbol is IFieldSymbol symbol) {
                location = memberAccess.Name.GetLocation();
                fieldSymbol = symbol;
            }
        } else if (context.Node is IdentifierNameSyntax identifierNameSyntax) {
            // 排除字段声明场景（只检测使用场景）
            if (IsPartOfFieldDeclaration(identifierNameSyntax)) {
                return;
            }
            var targetSymbol = context.SemanticModel.GetSymbolInfo(identifierNameSyntax).Symbol;
            if (targetSymbol is IFieldSymbol symbol) {
                location = identifierNameSyntax.GetLocation();
                fieldSymbol = symbol;
            }
        }

        if (fieldSymbol == null) {
            return;
        }

        if (IsInStrictCompliantPropertyGetter(context.Node)) {
            return;
        }

        // 检查字段是否标记了 [FileField]
        if (CheckAndReportFieldUsage(fieldSymbol, fileFieldAttributeSymbol)) {
            context.ReportDiagnostic(Diagnostic.Create(
                FileFieldAttributeRestrictionDiagnostic.Rule,
                location,
                fieldSymbol.Name
            ));
        }
    }

    /// <summary>
    /// 判断当前节点是否处于「严格合规的属性getter」中
    /// 合规定义：无setter + 仅允许 field__xxx__ / this.field__xxx__ 表达式
    /// </summary>
    private bool IsInStrictCompliantPropertyGetter(SyntaxNode currentNode) {
        var parentNode = currentNode;
        PropertyDeclarationSyntax targetProperty = null;

        // 先定位到属性声明节点，检查是否包含setter
        while (parentNode != null) {
            if (parentNode is PropertyDeclarationSyntax prop) {
                targetProperty = prop;
                break;
            }
            parentNode = parentNode.Parent;
        }

        // 关键限制：属性不能有任何setter（包括私有setter）
        if (targetProperty != null && HasSetter(targetProperty)) {
            return false;
        }

        // 重新遍历，检查getter内容是否合规
        parentNode = currentNode;
        while (parentNode != null) {
            // 场景1：传统表达式体属性（如 private T Prop => field__xxx__;）
            if (parentNode is PropertyDeclarationSyntax propDecl && propDecl.ExpressionBody != null) {
                return IsStrictAllowedExpression(propDecl.ExpressionBody.Expression);
            }

            // 场景2：表达式体访问器（如 get => field__xxx__;）
            if (parentNode is AccessorDeclarationSyntax exprBodyAccessor &&
                exprBodyAccessor.IsKind(SyntaxKind.GetAccessorDeclaration) &&
                exprBodyAccessor.ExpressionBody != null) {
                return IsStrictAllowedExpression(exprBodyAccessor.ExpressionBody.Expression);
            }

            // 场景3：传统显式访问器（如 get { return field__xxx__; }）
            if (parentNode is AccessorDeclarationSyntax blockAccessor &&
                blockAccessor.IsKind(SyntaxKind.GetAccessorDeclaration) &&
                blockAccessor.Body != null) {

                var getterStatements = blockAccessor.Body.Statements;
                // 强制要求：仅1条return语句 + 表达式合规
                return getterStatements.Count == 1
                       && getterStatements[0] is ReturnStatementSyntax returnStmt
                       && returnStmt.Expression != null
                       && IsStrictAllowedExpression(returnStmt.Expression);
            }

            parentNode = parentNode.Parent;
        }
        return false;
    }

    /// <summary>
    /// 检查属性是否包含任何setter（包括public、private、init等）
    /// </summary>
    public bool HasSetter(PropertyDeclarationSyntax property) {
        // 检查是否有显式set访问器（如 set; 或 set { ... }）
        bool hasExplicitSetter = property.AccessorList?.Accessors
            .Any(a => a.IsKind(SyntaxKind.SetAccessorDeclaration)) ?? false;

        // 检查是否有自动实现的setter（如 { get; set; } 或 { get; private set; }）
        bool hasAutoSetter = property.AccessorList?.Accessors
            .Any(a => a.IsKind(SyntaxKind.SetAccessorDeclaration) && a.Body == null) ?? false;

        return hasExplicitSetter || hasAutoSetter;
    }

    /// <summary>
    /// 严格判断：仅允许 field__xxx__ 或 this.field__xxx__（无任何附加逻辑）
    /// </summary>
    public bool IsStrictAllowedExpression(ExpressionSyntax expression) {
        // 情况1：纯字段名（如 field__GlobalInterfaceOne__）
        if (expression is IdentifierNameSyntax identifier) {
            return identifier.Identifier.Text.StartsWith("field__");
        }

        // 情况2：this.字段名（如 this.field__GlobalInterfaceOne__）
        if (expression is MemberAccessExpressionSyntax memberAccess) {
            bool isLeftThis = memberAccess.Expression is ThisExpressionSyntax;
            bool isRightValidField = memberAccess.Name is IdentifierNameSyntax fieldIdent
                                     && fieldIdent.Identifier.Text.StartsWith("field__");

            return isLeftThis && isRightValidField;
        }

        // 其他情况均不允许
        return false;
    }

    /// <summary>
    /// 判断标识符是否属于字段声明（避免检测声明语句本身）
    /// </summary>
    private bool IsPartOfFieldDeclaration(IdentifierNameSyntax identifier) {
        return identifier.Ancestors().Any(n => n is FieldDeclarationSyntax);
    }

    /// <summary>
    /// 核心逻辑：检查字段是否标记了 [FileField] 并报告错误
    /// </summary>
    private bool CheckAndReportFieldUsage(IFieldSymbol fieldSymbol, INamedTypeSymbol fileFieldAttributeSymbol) {
        if (fieldSymbol == null) {
            return false;
        }
        var attributeData = fieldSymbol.GetAttributes(fileFieldAttributeSymbol).FirstOrDefault();
        if (attributeData == null) {
            return false;
        }
        return true;
    }
}